package com.yahoo.labs.snow;

import it.unimi.dsi.fastutil.ints.IntOpenHashSet;

import java.util.Comparator;

import cern.colt.Sorting;

import com.yahoo.labs.snow.util.Id2Str;

/**
 * Represents a snowflake.
 * 
 * @author chato
 *
 */
public class Snowflake {

	/**
	 * The elements this snowflake is composed of.
	 */
	final IntOpenHashSet elements;

	/**
	 * The problem instance for which this snowflake was generated.
	 */
	final ProblemInstance problem;

	public Snowflake(IntOpenHashSet elements, ProblemInstance problem) {
		this.elements = new IntOpenHashSet(elements); // clone
		this.problem = problem;
	}

	public double getCost() {
		int sumCosts = 0;
		for (int id : elements) {
			sumCosts += problem.getCost(id);
		}
		return sumCosts;
	}
	

	public int getCoverSize() {
		IntOpenHashSet covered = new IntOpenHashSet();
		for (int id : elements) {
			covered.addAll(problem.getCover(id));
		}
		return covered.size();
	}

	public String toString(Id2Str node2name) {
		StringBuffer sb = new StringBuffer();
		
		for (int id : elements) {
			sb.append(" * " + id + (node2name == null ? "" : " " + node2name.getNameByNode(problem.getNode(id))));
			sb.append(" (cost=" + problem.getCost(id) + ")\n");
		}
		sb.append(" SIZE             = " + elements.size() + "\n");
		sb.append(" COVERAGE         = " + getCoverSize() + "\n");
		sb.append(" COST             = " + getCost() + "\n");
		sb.append(" MIN_INTRA_COMPAT = " + getMinCompat() + "\n");
		sb.append(" SUM_INTRA_COMPAT = " + getSumIntraCompat() + "\n");
		return sb.toString();
	}

	public double getSumIntraCompat() {
		double sum = 0.0;
		for (int id1 : elements) {
			for (int id2 : elements) {
				sum += problem.getCompat(id1, id2);
			}
		}
		return sum;
	}

	private double getMinCompat() {
		double minCompat = Double.MAX_VALUE;
		for (int node1 : elements) {
			for (int node2 : elements) {
				double compat = problem.getCompat(node1, node2);
				if (compat > 0 && compat < minCompat) {
					minCompat = compat;
				}
			}
		}
		if (minCompat == Double.MAX_VALUE) {
			minCompat = 0.0; // No non-zero compatibility values
		}
		return minCompat;
	}

	public static void sortByDecreasingSumCompat(Snowflake[] snowflakes) {
		Sorting.quickSort(snowflakes, new Comparator<Snowflake>() {
			@Override
			public int compare(Snowflake s1, Snowflake s2) {
				return (int) Math.signum(s2.getSumIntraCompat() - s1.getSumIntraCompat());
			}
		});
	}

	public IntOpenHashSet ids() {
		return elements;
	}
	
	@Override
	public String toString() {
		return elements.toString();
	}
}
